using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

using Walkmen.ID3v1;
using Walkmen.ID3v2;
using Walkmen.OpenMG;
using Walkmen.Util;

namespace Walkmen.Convert
{
    public class OMAConverter
    {
        private const string ALBUM_UNKNOWN = "Unknown";
        private const string TITLE_UNKNOWN = "Unknown";

        private readonly string _outDir;
        private readonly string _encoding;

        public OMAConverter(string outDir, string encoding)
        {
            _outDir = outDir;
            _encoding = encoding;
        }

        private ID3v2Header ConvertHeader(OMAHeader omaHeader)
        {
            ID3v2Header id3Header = new ID3v2Header();
            id3Header.FileType = "ID3";
            id3Header.Version = 0x0300;

            ConvertContext ctx = new ConvertContext(id3Header, _encoding);

            foreach (OMAFrame frame in omaHeader.Frames)
            {
                FrameHandlerFactory factory = FrameHandlerFactory.GetInstance();
                IFrameHandler handler = factory.GetHandler(frame.FrameId);

                if (handler != null)
                {
                    handler.Handle(ctx, frame);
                }
            }

            return id3Header;
        }

        private string CreateOutputFileName(Song song)
        {
        	string dirName = null;
			if (String.IsNullOrEmpty(song.Album))
			{
            	dirName = Path.Combine(_outDir, ALBUM_UNKNOWN);
            }
            else
            {
                dirName = Path.Combine(_outDir, StringUtils.EscapeFilePath(song.Album));
            }

            if (!Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }

            string fileName = null;
            if (String.IsNullOrEmpty(song.Title))
            {
                fileName = String.Format("{0:D2}_{1}.mp3", song.Track, TITLE_UNKNOWN);
            }
            else
            {
                fileName = String.Format("{0:D2}_{1}.mp3", song.Track, StringUtils.EscapeFilePath(song.Title));
            }

            int index = 1;
            while (File.Exists(Path.Combine(dirName, fileName)))
            {
                fileName = String.Format("({0}){1}", index, fileName);
                index++;
            }

            return Path.Combine(dirName, fileName);
        }

        public void Convert(string fileName)
        {
            using (Stream stream = new BufferedStream(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
            {
                OMAHeader omaHeader = OMAHeader.Parse(stream);

                OpenMGHeader omgHeader = OpenMGHeader.Parse(stream);

                Song song = Song.Parse(omaHeader.Frames);

                string outfile = CreateOutputFileName(song);

                using (Stream output = new BufferedStream(new FileStream(outfile, FileMode.Create, FileAccess.Write, FileShare.Read)))
                {
                    ID3v2Header id3Header = ConvertHeader(omaHeader);

                    byte[] binHeader = id3Header.ToArray();
                    output.Write(binHeader, 0, binHeader.Length);

                    byte[] data = new byte[8192];
                    int r = 0;
                    while ((r = stream.Read(data, 0, data.Length)) > 0)
                    {
                        output.Write(data, 0, r);
                    }
                }
            }
        }
    }
}
